package com.xdemo.personal.handler;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.FileCleaningTracker;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.DynamicChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.codec.http.HttpVersion;

import com.xdemo.core.MessageType;
import com.xdemo.handler.IMessageAction;
import com.xdemo.manager.ShortUrlDao;
import com.xdemo.model.ShortUrl;
import com.xdemo.msg.IMessage;
import com.xdemo.personal.fileupload.IFileProcessor;
import com.xdemo.personal.fileupload.IFileStore;
import com.xdemo.personal.fileupload.NettyFileUpload;
import com.xdemo.personal.fileupload.NettyRequestContext;
import com.xdemo.personal.fileupload.SimpleFileProcessor;
import com.xdemo.personal.fileupload.SingleDirectoryStore;
import com.xdemo.personal.httpserver.HttpRequestShortUrlMsg;
import com.xdemo.personal.httpserver.msg.FileSizeTooLargeMessage;
import com.xdemo.personal.httpserver.msg.FileUploadMessage;
import com.xdemo.personal.httpserver.msg.FileUploadServiceBusyMessage;
import com.xdemo.personal.httpserver.msg.FileUploadUnknownErrorMsg;
import com.xdemo.personal.manager.DaoManager;
import com.xdemo.personal.server.pool.EManager;
import com.xdemo.personal.server.pool.ManagerPool;

public class FileUploadAction implements IMessageAction<String> {

	private String[] types = { MessageType.FileUpload,
								MessageType.FileSizeTooLarge,
								MessageType.FileUploadServiceBusy,
								MessageType.FileUploadUnknownError,
								MessageType.FileRequestShortUrl};
	
	private DiskFileItemFactory itemFactory = new DiskFileItemFactory();
	private NettyFileUpload fileUploader;
	private IFileStore store;
	private IFileProcessor fileProcessor;
	private final Pattern shortUrlPattern = Pattern.compile("/[a-z|0-9]{8}");
	
	public FileUploadAction() {
		itemFactory.setRepository(new File("D:/dev/workspace/xdemo/tmp"));
		itemFactory.setFileCleaningTracker(new FileCleaningTracker());
		fileUploader = new NettyFileUpload(itemFactory);
		store = new SingleDirectoryStore("D:/dev/workspace/xdemo/upload");
		fileProcessor = new SimpleFileProcessor();
	}

	@Override
	public void doAction(IMessage<String> message) {
		if (message.getType().equals(MessageType.FileUpload)) {
			doUpdate((FileUploadMessage) message);
		}else if(message.getType().equals(MessageType.FileSizeTooLarge)) {
			doFileSizeTooLarge((FileSizeTooLargeMessage)message);
		}else if(message.getType().equals(MessageType.FileUploadServiceBusy)) {
			doFileUploadServiceBusy((FileUploadServiceBusyMessage)message);
		}else if(message.getType().equals(MessageType.FileUploadUnknownError)) {
			doFileUnknownError((FileUploadUnknownErrorMsg)message);
		}else if(message.getType().equals(MessageType.FileRequestShortUrl)) {
			doFileRequestShortUrl((HttpRequestShortUrlMsg)message);
		}
	}
	
	@Override
	public String[] getTypes() {
		return types;
	}

	private void doUpdate(FileUploadMessage message) {
		ChannelHandlerContext _context = message.getContext();
		try {
			if (!NettyFileUpload.isMultipartContent(message)) {
				return;
			}
			NettyRequestContext _nettyContext = new NettyRequestContext("UTF-8",message.getHeader("Content-Type"), -1, message.getChunkedStream());
			fileUploader.setContext(_nettyContext);
			List<?> _result = fileUploader.parseRequest(_nettyContext);
			DiskFileItem _item = (DiskFileItem)_result.get(0);
			ShortUrl _url = fileProcessor.processorFile(store,_item);
			if(_url != null) {
				this.onUploadSuccess(_context,_url);
			}else{
				this.onUploadFail(_context);
			}
		} catch(Exception e){
			e.printStackTrace();
		}
	}
	
	private void onUploadSuccess(ChannelHandlerContext context,ShortUrl url) {
		HttpResponse _response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
		ChannelBuffer _buffer=new DynamicChannelBuffer(2048);
		_buffer.writeBytes(("send successful!<a href=\"http://10.2.10.146:8080/"+url.getUrl()+"\"/>"+ "http://10.2.10.146:8080/" + url.getUrl() +"</a>").getBytes());
		_response.setContent(_buffer);
		_response.setHeader("Content-Type", "text/html; charset=UTF-8");
		_response.setHeader("Content-Length", _response.getContent().writerIndex());
		Channel _channel = context.getChannel();
		_channel.write(_response).addListener(ChannelFutureListener.CLOSE);
	}
	
	private void onUploadFail(ChannelHandlerContext context) {
		HttpResponse _response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
		ChannelBuffer _buffer=new DynamicChannelBuffer(2048);
		_buffer.writeBytes("server internal error,try later!".getBytes());
		_response.setContent(_buffer);
		_response.setHeader("Content-Type", "text/html; charset=UTF-8");
		_response.setHeader("Content-Length", _response.getContent().writerIndex());
		Channel _channel = context.getChannel();
		_channel.write(_response).addListener(ChannelFutureListener.CLOSE);
	}
	
	private void doFileSizeTooLarge(FileSizeTooLargeMessage message) {
		ChannelHandlerContext _context = message.getContext();
		HttpResponse _response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
		ChannelBuffer _buffer=new DynamicChannelBuffer(2048);
		_buffer.writeBytes("sorry,file too large!".getBytes());
		_response.setContent(_buffer);
		_response.setHeader("Content-Type", "text/html; charset=UTF-8");
		_response.setHeader("Content-Length", _response.getContent().writerIndex());
		Channel _channel = _context.getChannel();
		_channel.write(_response).addListener(ChannelFutureListener.CLOSE);
	}
	
	private void doFileUploadServiceBusy(FileUploadServiceBusyMessage message) {
		ChannelHandlerContext _context = message.getContext();
		HttpResponse _response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
		ChannelBuffer _buffer=new DynamicChannelBuffer(2048);
		_buffer.writeBytes("sorry,file service busy,try later!".getBytes());
		_response.setContent(_buffer);
		_response.setHeader("Content-Type", "text/html; charset=UTF-8");
		_response.setHeader("Content-Length", _response.getContent().writerIndex());
		Channel _channel = _context.getChannel();
		_channel.write(_response).addListener(ChannelFutureListener.CLOSE);
	}
	
	private void doFileUnknownError(FileUploadUnknownErrorMsg message) {
		ChannelHandlerContext _context = message.getContext();
		HttpResponse _response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
		ChannelBuffer _buffer=new DynamicChannelBuffer(2048);
		_buffer.writeBytes("sorry,http request format unknown error!".getBytes());
		_response.setContent(_buffer);
		_response.setHeader("Content-Type", "text/html; charset=UTF-8");
		_response.setHeader("Content-Length", _response.getContent().writerIndex());
		Channel _channel = _context.getChannel();
		_channel.write(_response).addListener(ChannelFutureListener.CLOSE);
	}
	
	private void doFileRequestShortUrl(HttpRequestShortUrlMsg message) {
		String _shortUrl = message.getShortUrl();
		if(shortUrlPattern.matcher(_shortUrl).find()) {
			_shortUrl = _shortUrl.substring(1);
		}else{
			return;
		}
		ChannelHandlerContext _context = message.getContext();
		DaoManager _daoManager = (DaoManager)ManagerPool.getManager(EManager.DAO);
		ShortUrlDao _shortUrlDao = _daoManager.getShortUrlDao();
		ShortUrl _url = _shortUrlDao.get(ShortUrl.class, _shortUrl);
		System.out.println(_url.getFileName());
		try {
			InputStream _stream = new FileInputStream(_url.getLocation());
			BufferedInputStream _bufferedStream = new BufferedInputStream(_stream);
			HttpResponse _response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
			String _ext = _url.getFileName().substring(_url.getFileName().indexOf('.') + 1);
			_response.setHeader("Content-Type", "image/"+_ext.toLowerCase());
			ChannelBuffer _buffer = new DynamicChannelBuffer(1024);
			byte[] _content = new byte[1024];
			Channel _channel = _context.getChannel();
			while(_bufferedStream.available() > 0) {
				int _len = _bufferedStream.read(_content);
				_buffer.writeBytes(_content, 0, _len);
			}
			_bufferedStream.close();
			_response.setContent(_buffer);
			_channel.write(_response).addListener(ChannelFutureListener.CLOSE);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
